﻿#include "box_config_impl.hh"
#include "../../thirdparty/kconfig/kconfig/interface/config.h"
#include "../../thirdparty/kconfig/kconfig/interface/config_factory.h"
#include "../box/service_box.hh"
#include "../util/os_util.hh"
#include "lang_impl.hh"

namespace kratos {
namespace config {

BoxConfigImpl::BoxConfigImpl(kratos::service::ServiceBox *box) { box_ = box; }

BoxConfigImpl::~BoxConfigImpl() {}

auto BoxConfigImpl::load(const std::string &config_file_path,
                         std::string &error) -> bool {
  config_.reset(ConfigFactory::createConfig());
  config_file_path_ = config_file_path;
  try {
    config_->load("", config_file_path);
  } catch (std::exception &ex) {
    error = ex.what();
    return false;
  }
  if (config_->has("listener.host")) {
    auto *listener_list_array = config_->array("listener.host");
    for (int i = 0; i < listener_list_array->getSize(); i++) {
      listener_list_.push_back(listener_list_array->string(i)->get());
    }
    if (listener_list_.empty()) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "listener.host");
      }
      return false;
    }
  }
  if (config_->has("service_finder.type")) {
    finder_type_ = config_->string("service_finder.type")->get();
    if (finder_type_.empty()) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "service_finder.type");
      }
      return false;
    }
  }
  if (config_->has("service_finder.hosts")) {
    finder_hosts_ = config_->string("service_finder.hosts")->get();
    if (finder_hosts_.empty()) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "service_finder.hosts");
      }
      return false;
    }
  }
  if (config_->has("box_channel_recv_buffer_len")) {
    box_channel_recv_buffer_len_ =
        static_cast<int>(config_->getInt32("box_channel_recv_buffer_len"));
    if (box_channel_recv_buffer_len_ <= 0) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "box_channel_recv_buffer_len");
      }
      return false;
    }
  }
  if (config_->has("box_name")) {
    box_name_ = config_->string("box_name")->get();
    if (box_name_.empty()) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "box_name");
      }
      return false;
    }
  }
  if (config_->has("logger_config_line")) {
    logger_config_line_ = config_->string("logger_config_line")->get();
    if (logger_config_line_.empty()) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "logger_config_line");
      }
      return false;
    }
  }
  if (config_->has("service.service_dir")) {
    service_dir_ = config_->string("service.service_dir")->get();
    /*if (!kratos::util::is_path_exists(service_dir_)) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "service.service_dir");
      }
      return false;
    }*/
  }
  if (config_->has("service.preload_service")) {
    auto *preload_service_table = config_->table("service.preload_service");
    while (preload_service_table->hasNext()) {
      auto *pair = preload_service_table->next();
      service_map_[pair->key()] = pair->value()->string()->get();
    }
  }
  if (config_->has("connect_other_box_timeout")) {
    connect_other_box_timeout_ =
        static_cast<int>(config_->getInt32("connect_other_box_timeout"));
    if (connect_other_box_timeout_ <= 0) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "connect_other_box_timeout");
      }
      return false;
    }
  }
  if (config_->has("service_finder_connect_timeout")) {
    service_finder_connect_timeout_ =
        static_cast<int>(config_->getUint32("service_finder_connect_timeout"));
    if (service_finder_connect_timeout_ <= 0) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "service_finder_connect_timeout");
      }
      return false;
    }
  }
  if (config_->has("necessary_service")) {
    auto *services = config_->array("necessary_service");
    for (int i = 0; i < services->getSize(); i++) {
      necessary_service_.push_back(services->string(i)->get());
    }
  }
  if (config_->has("open_coroutine")) {
    is_open_coroutine_ = config_->string("open_coroutine")->get() == "true";
  }
  if (config_->has("service.remote_service_repo_version_api")) {
    remote_service_repo_version_api_ =
        config_->string("service.remote_service_repo_version_api")->get();
  }
  if (config_->has("service.remote_service_repo_dir")) {
    remote_service_repo_dir_ =
        config_->string("service.remote_service_repo_dir")->get();
  }
  if (config_->has("service.remote_service_repo_latest_version_api")) {
    remote_service_repo_latest_version_api_ =
        config_->string("service.remote_service_repo_latest_version_api")
            ->get();
  }
  if (config_->has("service.is_open_remote_update")) {
    is_open_remote_update_ =
        (config_->string("service.is_open_remote_update")->get() == "true");
  }
  if (config_->has("service.remote_repo_check_interval")) {
    remote_repo_check_interval_ = static_cast<int>(
        config_->getInt32("service.remote_repo_check_interval"));
    if (remote_repo_check_interval_ <= 0) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "service.remote_repo_check_interval");
      }
      return false;
    }
  }
  if (config_->has("service.is_start_as_daemon")) {
    is_start_as_daemon_ =
        (config_->string("service.is_start_as_daemon")->get() == "true");
  }
  if (config_->has("http.http_max_call_timeout")) {
    http_max_call_timeout_ = config_->getInt32("http.http_max_call_timeout");
    if (http_max_call_timeout_ <= 0) {
      if (box_) {
        box_->write_log(lang::LangID::LANG_CONFIG_ERROR, klogger::Logger::FATAL,
                        "http.http_max_call_timeout");
      }
      return false;
    }
  }
  if (config_->has("statistics.is_open_rpc_stat")) {
    is_open_rpc_stat_ =
        (config_->string("statistics.is_open_rpc_stat")->get() == "true");
  }
  return true;
}

auto BoxConfigImpl::reload(const std::string &config_file_path,
                           std::string &error) -> bool {
  BoxConfigImpl new_box_config(box_);
  if (!new_box_config.load(config_file_path, error)) {
    return false;
  }
  // 调用事件监听器
  call_reload_listener(new_box_config);
  *this = std::move(new_box_config);
  return true;
}

auto BoxConfigImpl::add_reload_listener(const std::string &name,
                                        ReloadListener listener) -> bool {
  reload_listener_map_[name] = listener;
  return true;
}

auto BoxConfigImpl::remove_reload_listener(const std::string &name) -> bool {
  reload_listener_map_.erase(name);
  return true;
}

auto BoxConfigImpl::get_config_ptr() -> kconfig::Config * {
  return config_.get();
}

auto BoxConfigImpl::get_listener_list() const
    -> const std::vector<std::string> & {
  return listener_list_;
}

auto BoxConfigImpl::get_service_finder_type() const -> const std::string & {
  return finder_type_;
}

auto BoxConfigImpl::get_service_finder_hosts() const -> const std::string & {
  return finder_hosts_;
}

auto BoxConfigImpl::get_service_finder_connect_timeout() const -> std::time_t {
  return service_finder_connect_timeout_;
}

auto BoxConfigImpl::set_service_finder_connect_timeout(
    std::time_t timeout) const -> void {
  auto *mutable_this = const_cast<BoxConfigImpl *>(this);
  mutable_this->service_finder_connect_timeout_ = timeout;
  mutable_this->call_reload_listener(*this);
}

auto BoxConfigImpl::get_necessary_service() const
    -> const std::vector<std::string> & {
  return necessary_service_;
}

auto BoxConfigImpl::get_connect_other_box_timeout() const -> int {
  return connect_other_box_timeout_;
}

auto BoxConfigImpl::get_box_channel_recv_buffer_len() const -> int {
  return box_channel_recv_buffer_len_;
}

auto BoxConfigImpl::get_box_name() const -> const std::string & {
  return box_name_;
}

auto BoxConfigImpl::get_logger_config_line() const -> const std::string & {
  return logger_config_line_;
}

auto BoxConfigImpl::get_service_dir() const -> const std::string & {
  return service_dir_;
}

auto BoxConfigImpl::get_preload_service() const
    -> const std::unordered_map<std::string, std::string> & {
  return service_map_;
}

auto BoxConfigImpl::is_open_coroutine() const -> bool {
  return is_open_coroutine_;
}

auto BoxConfigImpl::get_remote_service_repo_version_api() const
    -> const std::string & {
  return remote_service_repo_version_api_;
}

auto BoxConfigImpl::get_remote_service_repo_dir() const -> const std::string & {
  return remote_service_repo_dir_;
}

auto BoxConfigImpl::get_remote_service_repo_latest_version_api() const
    -> const std::string & {
  return remote_service_repo_latest_version_api_;
}

auto BoxConfigImpl::is_open_remote_update() const -> bool {
  return is_open_remote_update_;
}

auto BoxConfigImpl::get_remote_repo_check_interval() const -> int {
  return remote_repo_check_interval_;
}

auto BoxConfigImpl::is_start_as_daemon() const -> bool {
  return is_start_as_daemon_;
}

auto BoxConfigImpl::get_http_max_call_timeout() const -> int {
  return http_max_call_timeout_;
}

auto BoxConfigImpl::is_open_rpc_stat() -> bool { return is_open_rpc_stat_; }

auto BoxConfigImpl::has_attribute(const std::string &name) -> bool {
  return config_->has(name);
}

auto BoxConfigImpl::get_config_file_path() const -> const std::string & {
  return config_file_path_;
}

auto BoxConfigImpl::set_service_finder_connect_timeout(int timeout) -> void {
  service_finder_connect_timeout_ = timeout;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_connect_other_box_timeout(int timeout) -> void {
  connect_other_box_timeout_ = timeout;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_box_channel_recv_buffer_len(int len) -> void {
  box_channel_recv_buffer_len_ = len;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_http_max_call_timeout(int timeout) -> void {
  http_max_call_timeout_ = timeout;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_is_open_remote_update(bool on_off) -> void {
  is_open_remote_update_ = on_off;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_is_open_rpc_stat(bool value) -> void {
  is_open_rpc_stat_ = value;
  call_reload_listener(*this);
}

auto BoxConfigImpl::set_remote_repo_check_interval(int second) -> void {
  remote_repo_check_interval_ = second;
  call_reload_listener(*this);
}

auto BoxConfigImpl::copy_attribute(const BoxConfigImpl &rht) -> void {
  listener_list_ = rht.listener_list_;
  finder_type_ = rht.finder_type_;
  finder_hosts_ = rht.finder_hosts_;
  service_finder_connect_timeout_ = rht.service_finder_connect_timeout_;
  necessary_service_ = rht.necessary_service_;
  connect_other_box_timeout_ = rht.connect_other_box_timeout_;
  box_channel_recv_buffer_len_ = rht.box_channel_recv_buffer_len_;
  box_name_ = rht.box_name_;
  logger_config_line_ = rht.logger_config_line_;
  service_dir_ = rht.service_dir_;
  service_map_ = rht.service_map_;
  is_open_coroutine_ = rht.is_open_coroutine_;
  remote_service_repo_version_api_ = rht.remote_service_repo_version_api_;
  remote_service_repo_latest_version_api_ =
      rht.remote_service_repo_latest_version_api_;
  remote_service_repo_dir_ = rht.remote_service_repo_dir_;
  is_open_remote_update_ = rht.is_open_remote_update_;
  remote_repo_check_interval_ = rht.remote_repo_check_interval_;
  is_start_as_daemon_ = rht.is_start_as_daemon_;
  http_max_call_timeout_ = rht.http_max_call_timeout_;
  is_open_rpc_stat_ = rht.is_open_rpc_stat_;
}

auto BoxConfigImpl::operator=(BoxConfigImpl &&rht) noexcept
    -> const BoxConfigImpl & {
  listener_list_ = std::move(rht.listener_list_);
  finder_type_ = rht.finder_type_;
  finder_hosts_ = rht.finder_hosts_;
  service_finder_connect_timeout_ = rht.service_finder_connect_timeout_;
  necessary_service_ = std::move(rht.necessary_service_);
  connect_other_box_timeout_ = rht.connect_other_box_timeout_;
  config_ = std::move(rht.config_);
  box_channel_recv_buffer_len_ = rht.box_channel_recv_buffer_len_;
  box_name_ = std::move(rht.box_name_);
  logger_config_line_ = std::move(rht.logger_config_line_);
  service_dir_ = std::move(rht.service_dir_);
  service_map_ = std::move(rht.service_map_);
  is_open_coroutine_ = rht.is_open_coroutine_;
  remote_service_repo_version_api_ =
      std::move(rht.remote_service_repo_version_api_);
  remote_service_repo_latest_version_api_ =
      std::move(rht.remote_service_repo_latest_version_api_);
  remote_service_repo_dir_ = std::move(rht.remote_service_repo_dir_);
  is_open_remote_update_ = rht.is_open_remote_update_;
  remote_repo_check_interval_ = rht.remote_repo_check_interval_;
  is_start_as_daemon_ = rht.is_start_as_daemon_;
  http_max_call_timeout_ = rht.http_max_call_timeout_;
  is_open_rpc_stat_ = rht.is_open_rpc_stat_;
  return *this;
}

auto BoxConfigImpl::call_reload_listener(const BoxConfigImpl &config) -> void {
  for (const auto &[name, method] : reload_listener_map_) {
    method(name, config);
  }
}

} // namespace config
} // namespace kratos
